package TCPEchoServerAndAlient;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

/**
 * Description:
 * User:岁亮亮
 * Date:2025-04-06
 * TIME:13:58
 */
public class TCPEchoServer {

    //服务器专用的socket对象
    ServerSocket serverSocket = null;

    public TCPEchoServer(int port) throws IOException {
        serverSocket = new ServerSocket(port);

    }


    /**
     *  首先了解一下Socket 与 ServerSocket区别
     *  1.Socket服务器和客户端都可以使用的 ServerSocket专用于服务器
     *  2.为什么呢?
     *   TCP是有链接的 在客户端中caiyongTCP协议发送数据报
     *   首先会在客户端的操作系统内核向目标服务器发送请求链接 相当于拨号  服务器可以选择接听 这时客户端与服务器就建立连接了
     *   建立连接完成后服务器将建立起来的连接交给 实际处理客户端请求的对象 服务器继续监听客户端发来的连接请求
     *   因此ServerSocket对象是 处理监听客户端发来的连接请求
     *  Socket对象是实际上是处理对客户端 进行通信并处理请求并发送响应
     *
     * @throws IOException
     */
    public void start() throws IOException {
        System.out.println("服务器启动");
        while(true){
            //
            Socket socket = serverSocket.accept();
            System.out.printf(" 客户端 [%s]  上线",socket.getInetAddress());
            processSocket(socket);
        }

    }
    //处理
    private void processSocket(Socket socket) throws IOException {
        System.out.println();
        Scanner scanner = new Scanner(socket.getInputStream());
        while(true){
            //读取客户端发来的请求
            //1.1TCP是面向字节流传输的不用创建专门的类进行接收 可以直接使用字节数组进行接收
            //1.2也可以用Scanner来读取
            if(!scanner.hasNext()){
                System.out.printf("客户端[%s] 下线",socket.getInetAddress());
                break;
            }
            //这里规定 客户端发来的请求以 空白符结尾 如果不是则服务器会读取失败
            String request = scanner.next();

            //根据请求构造响应
            String response = process(request);
            //发送响应
            //3.1 可以根据字符串构造一个字节数组 通过OutStream发送 但添加空白符很麻烦
            //3.2 可以使用跟Scanner类似的输出类PrintrWriter进行发送
            PrintWriter printWriter = new PrintWriter(socket.getOutputStream());
            printWriter.println(response);
            printWriter.flush();
            //打印日志
            System.out.printf("[%s %d] resp : %s resq :: %s",socket.getInetAddress(),socket.getPort(),
                                                     request,response);
            System.out.println();
        }
        //客户端下线之后要关闭这个socket对象 因为服务器同时会对多个客户端建立连接 会出现socket对象不够用的情况
        //而且socket对象在与客户端对话过程中持有文件描述符表 如果不关闭会一直占用对应的内存 GC不会对着一部分内存释放 引起文件资源的泄露
        socket.close();
    }

    private String process(String request) {
        return request;
    }

    public static void main(String[] args) throws IOException {
        TCPEchoServer tcpEchoServer = new TCPEchoServer(9090);
        tcpEchoServer.start();
    }
}
